package org.springframework.aop.framework.autoproxy;

import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.*;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.aop.framework.AopProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @Name DefaultAdvisorAutoProxyCreator
 * @Description: 目标 Bean 代理对象建造器
 * 描述信息: 当对象实例化时，生成代理对象并返回。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-03-28 15:17:07
 **/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
    private DefaultListableBeanFactory beanFactory;
    // 二级缓存中的 Bean 实例 AopProxy 代理引用集合
    private Set<Object> earlyProxyReferences = new HashSet<>();

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (!earlyProxyReferences.contains(beanName)) {
            return wrapIfNecessary(bean, beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        // Tips：如果此处返回代理 Bean 实例，则会 AbstractAutowireCapableBeanFactory.createBean() 方法导致短路，不再继续往下执行，而是直接返回代理 Bean 实例，从而造成无法为代理 Bean 设置属性的 Bug 问题。因此，此处必须返回 null。而把创建代理 Bean 实例的织入逻辑迁移至 postProcessAfterInitialization() 方法内执行。
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    private boolean isInfrastructureBean(Class<?> beanClass) {
        return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) {
        return pvs;
    }

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        earlyProxyReferences.add(beanName);
        return wrapIfNecessary(bean, beanName);
    }

    protected Object wrapIfNecessary(Object bean, String beanName) {
        // 避免死循环
        if (isInfrastructureBean(bean.getClass())) return bean;
        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
        try {
            AopProxyFactory aopProxyFactory = new AopProxyFactory();
            for (AspectJExpressionPointcutAdvisor advisor : advisors) {
                ClassFilter classFiter = advisor.getPointcut().getClassFilter();
                if (classFiter.filter(bean.getClass())) {
                    TargetSource targetSource = new TargetSource(bean);
                    aopProxyFactory.setTargetSource(targetSource);
                    aopProxyFactory.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
                    aopProxyFactory.addAdvisor(advisor);
                }
            }
            if (!aopProxyFactory.getAdvisors().isEmpty()) {
                return aopProxyFactory.getAopProxy();
            }
        } catch (Exception e) {
            throw new BeansException(beanName + " -> 创建代理 Bean 失败！", e);
        }
        return bean;
    }
}

